﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.ComponentModel;
using MediaPortal.Plugins.Trailers.Providers;
using MediaPortal.GUI.Library;

namespace MediaPortal.Plugins.Trailers
{
  public class TrailerData
  {
    public enum ActionType
    {
      Index = 0,
      Details = 1
    }
    public struct ProviderAction
    {
      public string Provider;
      public ActionType Action;
      public string Parameter;

      public ProviderAction(ActionType action, string provider, string parameter)
      {
        this.Provider = provider;
        this.Action = action;
        this.Parameter = parameter;
      }
    }

    private class IndexItemCache : Dictionary<string, Index>
    {

    } 
    private Dictionary<string, TrailerProviderBase> _providers = new Dictionary<string, TrailerProviderBase>();
    private Index _cacheProviders = new Index();
    private Dictionary<string, IndexItemCache> _cacheProviderIndex = new Dictionary<string,IndexItemCache>();
    private Dictionary<string, TrailerCollection> _cacheProviderTrailers = new Dictionary<string, TrailerCollection>();
    private string _selectedProvider = string.Empty;
    private BackgroundWorker _worker = new BackgroundWorker();
    public bool Cancelled = false;

    public string SelectProvider 
    {
      get {
        return _selectedProvider; 
      }
      set {
        _selectedProvider = value;
      }
    }

    public TrailerCollection Trailers
    {
      get { return _cacheProviderTrailers[_selectedProvider]; }
    }
    
    public TrailerProviderBase Provider
    {
      get { return _providers[_selectedProvider]; }
    }

    public Index GetProviders()
    {
      if (_cacheProviders.Count == 0)
      {
        foreach (KeyValuePair<string, TrailerProviderBase> provider in _providers)
        {
          IndexItem item = new IndexItem(provider.Value.ProviderName());
          item.Key = provider.Key;
          item.Image = provider.Value.ProviderImage();
          _cacheProviders.Add(item);
        }
      }
      return _cacheProviders;
    }

    public Index GetIndex()
    {
      return GetIndex(_selectedProvider, "", true);
    }

    public Index GetIndex(bool cache)
    {
      return GetIndex(_selectedProvider, "", cache);
    }

    public Index GetIndex(string key)
    {
      return GetIndex(_selectedProvider, key, true);
    }
    
    public Index GetIndex(string key, bool cache)
    {
      return GetIndex(_selectedProvider, key, cache);
    }

    public Index GetIndex(string provider, string key, bool cache)
    {
      Cancelled = false;
      if (!_cacheProviderIndex[provider].ContainsKey(key) || !cache)
        retrieveData(provider, ActionType.Index, key);

      if (_cacheProviderIndex[provider].ContainsKey(key))
        return _cacheProviderIndex[provider][key];
      else
        return null;   
    }

    public Trailer GetDetails(string key)
    {
      return GetDetails(key, true);
    }

    public Trailer GetDetails(string key, bool cache)
    {
      Trailer trailer;
      Cancelled = false;
      if (!_cacheProviderTrailers[_selectedProvider].ContainsKey(key) || !cache)
      {
        retrieveData(_selectedProvider, ActionType.Details, key);
        trailer = _cacheProviderTrailers[_selectedProvider][key];
        if (trailer != null)
          trailer.State = Trailer.InfoState.DETAIL;
      }
      else
      {
        trailer = _cacheProviderTrailers[_selectedProvider][key];
        if (trailer.State == Trailer.InfoState.INDEX || !cache)
        {
          retrieveData(_selectedProvider, ActionType.Details, key);
          if (trailer != null)
            trailer.State = Trailer.InfoState.DETAIL;
        }
      }
      return trailer;
    }

    private void loadProvider(TrailerProviderBase provider) {
      string providerId = provider.ProviderId();
      _providers.Add(providerId, provider);
      _cacheProviderIndex.Add(providerId, new IndexItemCache());
      _cacheProviderTrailers.Add(providerId, new TrailerCollection());
      provider.Init(_cacheProviderTrailers[providerId]);
      _selectedProvider = providerId;
    }

    public bool CancelData()
    {
      if (_worker.IsBusy)
      {
        _worker.CancelAsync();
        return true;
      }
      else
      {
        return false;
      }     
    }

    private bool retrieveData(string provider, ActionType action, string key)
    {
      ProviderAction providerAction = new ProviderAction(action, provider, key);
      if (!_worker.IsBusy)
      {
        _worker = new BackgroundWorker();
        _worker.WorkerSupportsCancellation = true;
        _worker.DoWork += new DoWorkEventHandler(dataWorker);
        _worker.RunWorkerAsync(providerAction);

        using (WaitCursor cursor = new WaitCursor())
        {
          while (_worker.IsBusy)
          {
            if (_worker.CancellationPending)
            {
              Cancelled = true;
              return false;
            }

            GUIWindowManager.Process();
          }
        }
        return true;
      }
      return false;
    }

    private void dataWorker(object sender, DoWorkEventArgs e)
    {
      Thread.CurrentThread.Name = "MyTrailersWorker";
      ProviderAction action = (ProviderAction)e.Argument;
      switch (action.Action)
      {
        case ActionType.Index:
          IndexItemCache cached = _cacheProviderIndex[action.Provider];
          if (action.Parameter != "")
            cached[action.Parameter] = _providers[action.Provider].GetIndex(action.Parameter);
          else
            cached[action.Parameter] = _providers[action.Provider].GetIndex();
          break;
        case ActionType.Details:
          _cacheProviderTrailers[action.Provider][action.Parameter] = _providers[action.Provider].GetDetails(action.Parameter);
          break;
      }
    }

    public TrailerData()
    {
      // Hardcoded: load available providers
      // Todo: make this dynamic
      TrailerProviderBase at = new AppleTrailers();
      loadProvider(at);
      TrailerProviderBase gt = new Gametrailers();
      loadProvider(gt);
      //TrailerProviderBase yt = new YahooTrailers();
      //loadProvider(yt);
    }

  }
}
